package com.uziot.bucket.dynamic.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author shidt
 * @version V1.0
 * @className SchedulerTaskRegistrar
 * @date 2020-11-21 23:24:52
 * @description 添加定时任务注册类，用来增加、删除定时任务。
 */
@Slf4j
@Component
public class SchedulerTaskRegistrar implements DisposableBean {

    private final Map<SchedulerRunnable, SchedulerTaskFuture>
            scheduledTasks = new ConcurrentHashMap<>(16);

    @Autowired
    private TaskScheduler taskScheduler;

    /**
     * 新增定时任务
     *
     * @param schedulerRunnable schedulerRunnable
     * @param cronExpression    cronExpression
     */
    public void addCronTask(SchedulerRunnable schedulerRunnable, String cronExpression) {
        CronTask cronTask = new CronTask(schedulerRunnable, cronExpression);
        this.addCronTask(cronTask);
    }

    /**
     * 新增定时任务
     *
     * @param cronTask cronTask
     */
    public void addCronTask(CronTask cronTask) {
        if (cronTask == null) {
            return;
        }
        // 新增定时任务，判定当前定时任务是否在执行中，如果是则先停止再新增
        SchedulerRunnable taskRunnable = (SchedulerRunnable) cronTask.getRunnable();
        this.scheduledTasks.forEach((task, future) -> {
            if (task.equals(taskRunnable)) {
                this.removeCronTask(task);
            }
        });
        SchedulerTaskFuture schedulerTaskFuture = this.scheduleCronTask(cronTask);
        this.scheduledTasks.put(taskRunnable, schedulerTaskFuture);
    }

    /**
     * 移除定时任务
     *
     * @param task task
     */
    public void removeCronTask(SchedulerRunnable task) {
        if (task == null) {
            return;
        }
        SchedulerTaskFuture schedulerTaskFuture = this.scheduledTasks.remove(task);
        if (schedulerTaskFuture != null) {
            schedulerTaskFuture.cancel();
            log.info("停止执行定时任务 - bean：{}，方法：{}，参数：{}",
                    task.getBeanName(), task.getMethodName(), Arrays.toString(task.getParams()));
        }
    }

    /**
     * 移除定时任务
     *
     * @param beanName 定时任务对象名称
     */
    public void removeCronTask(String beanName) {
        List<SchedulerRunnable> schedulerRunnableList = this.getSchedulerRunnable(beanName);
        schedulerRunnableList.forEach(this::removeCronTask);
    }

    /**
     * 移除定时任务
     *
     * @param beanName 定时任务对象名称
     */
    public void removeCronTask(String beanName, String methodName) {
        List<SchedulerRunnable> schedulerRunnableList = this.getSchedulerRunnable(beanName, methodName);
        schedulerRunnableList.forEach(this::removeCronTask);
    }

    /**
     * 创建定时任务计划
     *
     * @param cronTask cronTask
     * @return SchedulerTaskFuture
     */
    public SchedulerTaskFuture scheduleCronTask(CronTask cronTask) {
        SchedulerTaskFuture schedulerTaskFuture = new SchedulerTaskFuture();
        schedulerTaskFuture.scheduledFuture = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
        return schedulerTaskFuture;
    }

    /**
     * 销毁所有定时任务
     */
    @Override
    public void destroy() {
        scheduledTasks.forEach((task, future) -> {
            future.cancel();
            log.info("停止执行定时任务 - bean：{}，方法：{}，参数：{}",
                    task.getBeanName(), task.getMethodName(), Arrays.toString(task.getParams()));
        });
        int size = scheduledTasks.size();
        this.scheduledTasks.clear();
        log.info("清空定时任务执行列表,合计停止所有定时任务列表数量：[{}]", size);
    }

    /**
     * 获取任务执行调度线程池对象
     *
     * @return taskScheduler
     */
    public TaskScheduler getScheduler() {
        return this.taskScheduler;
    }

    /**
     * 获取定时任务线程和执行计划列表
     *
     * @return 列表map
     */
    public Map<SchedulerRunnable, SchedulerTaskFuture> getScheduledTasks() {
        return scheduledTasks;
    }

    /**
     * 获取执行中的定时任务列表
     *
     * @return 定时任务执行线程列表
     */
    public List<SchedulerRunnable> getSchedulerRunnable() {
        return new ArrayList<>(this.scheduledTasks.keySet());
    }

    /**
     * 根据Bean名称获得执行中的线程
     *
     * @param beanName beanName
     * @return 定时任务执行线程列表
     */
    public List<SchedulerRunnable> getSchedulerRunnable(String beanName) {
        ArrayList<SchedulerRunnable> schedulerRunnableList = new ArrayList<>();
        if (StringUtils.isEmpty(beanName)) {
            return schedulerRunnableList;
        }
        scheduledTasks.forEach((schedulerRunnable, schedulerTaskFuture) -> {
            String runnableBeanName = schedulerRunnable.getBeanName();
            if (beanName.equals(runnableBeanName)) {
                schedulerRunnableList.add(schedulerRunnable);
            }
        });
        return schedulerRunnableList;
    }

    /**
     * 根据类名和方法名获取线程
     *
     * @param beanName   beanName
     * @param methodName methodName
     * @return 定时任务执行线程列表
     */
    public List<SchedulerRunnable> getSchedulerRunnable(String beanName, String methodName) {
        ArrayList<SchedulerRunnable> schedulerRunnableList = new ArrayList<>();
        scheduledTasks.forEach((schedulerRunnable, schedulerTaskFuture) -> {
            String runnableBeanName = schedulerRunnable.getBeanName();
            String runnableMethodName = schedulerRunnable.getMethodName();
            if (beanName.equals(runnableBeanName) && methodName.equals(runnableMethodName)) {
                schedulerRunnableList.add(schedulerRunnable);
            }
        });
        return schedulerRunnableList;
    }


}
